package server;

import java.io.*;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Main implements Runnable {
  Socket csocket;
  private final ClientNode clients[];
  private final ServerGui serverGui;

  String REQUEST_USER_LIST = "users";
  String REQUEST_MAIL      = "mail";
  String REQUEST_ALL_DATA  = "all_data";
  String GLOBAL_MESSAGE    = "global";
  String QUIT              = "quit";
  String GET_UID           = "get_uid";
  
  String MSG_SEND          = "msg_send";
  String UPDATE            = "update";
  
  String SPLIT             = "_@@_";
  
  String UPDATE_NAME       = "name";
  String UPDATE_POS        = "pos"; //x,y,z pos
  
  static int BUFFER_LEN = 256;
  static int MAX_CLIENTS;
  static int port;
  static String serverName;
  
  Main(Socket csocket, ClientNode[] clients, ServerGui serverGui) {
    this.csocket = csocket;
    this.clients = clients;
    this.serverGui = serverGui;
  }

  public static void main(String args[]) throws Exception {

    AppConfig config = AppConfig.getInstance();
    port = config.getInt("wiichat.port");
    MAX_CLIENTS = config.getInt("wiichat.max_clients");
    serverName = config.getString("wiichat.server_name");

    ServerSocket ssock = new ServerSocket(port);
    ClientNode sclients[] = new ClientNode[MAX_CLIENTS];
    for(int i = 0; i < MAX_CLIENTS; i++) sclients[i] = new ClientNode();

    ServerGui tserverGui = new ServerGui(serverName, sclients, String.valueOf(port));
    tserverGui.setVisible(true);
    
    System.out.println("Listening");
    while (true) {
      Socket sock = ssock.accept();
      System.out.println("Connected");
      new Thread(new Main(sock,sclients,tserverGui)).start();
    }
  }

  public String handle_request(int client_id, String request)
  {
      if(request == null) return null;
      String[] parsed = request.split(SPLIT);
      
      if(parsed.length < 1) return null;
      
      if(parsed[0].equalsIgnoreCase(REQUEST_USER_LIST))
      {
          //Get names and return who is here
          System.out.println(clients[client_id].name +" requsted user list");
          String users = "~$"+REQUEST_USER_LIST+"$~";
          
          for(int i = 0; i < MAX_CLIENTS; i++)
          {
              if(clients[i].valid){
                  users += "[";
                  users += clients[i].name;
                  users += "]";        
              }
          }
          users += "\0";        
          return users;
      }
      else if(parsed[0].equalsIgnoreCase(REQUEST_ALL_DATA))
      {
          //Return positions of all users
          String out_str = "~$"+REQUEST_ALL_DATA+"$~";
          for(int i = 0; i < MAX_CLIENTS; i++)
          {
              if(clients[i].valid)
              {
                  out_str += "{UID[";
                  out_str += clients[i].uid;
                  out_str += "]";
                  out_str += "NAME[";
                  out_str += clients[i].name;
                  out_str += "]";
                  out_str += "POS[";
                  out_str += clients[i].x_pos;
                  out_str += ",";
                  out_str += clients[i].y_pos;
                  out_str += ",";
                  out_str += clients[i].z_pos;
                  out_str += "]";
                  out_str += "}";        
              }
          }
           out_str += "\0"; 
          return out_str;
      }
      else if(parsed[0].equalsIgnoreCase(GET_UID))
      {
           String outmsg = "~$"+GET_UID+"$~"+"UID[";
           outmsg += client_id;
           outmsg += "]\0";
           return outmsg;
      }
      else if(parsed[0].equalsIgnoreCase(REQUEST_MAIL))
      {
           if(!(clients[client_id].msg_in_box.isEmpty()))
           {
              String outmsg = "~$"+REQUEST_MAIL+"$~";
              outmsg += clients[client_id].msg_in_box;
              clients[client_id].msg_in_box = "";
              return outmsg;
           }
      }
      else if(parsed[0].equalsIgnoreCase(MSG_SEND))
      {
          if(parsed.length > 2)
          {
             //find client and put msg in box
              for(int i = 0; i < MAX_CLIENTS; i++)
              {
                  if(clients[i].valid)
                  {
                      if(clients[i].name.equalsIgnoreCase(parsed[1]) || parsed[1].equalsIgnoreCase(GLOBAL_MESSAGE)){
                          clients[i].msg_in_box += "[";
                          clients[i].msg_in_box += clients[client_id].name;
                          clients[i].msg_in_box += ">";
                          clients[i].msg_in_box += parsed[2];
                          clients[i].msg_in_box += "]";        
                      }
                      System.out.println(clients[client_id].name+">"+parsed[2]);
                  }
              }
             
          }
      }
      else if(parsed[0].equalsIgnoreCase(UPDATE))
      {
          if(parsed.length > 2)
          {
              if(parsed[1].equalsIgnoreCase(UPDATE_NAME))
              {
                  System.out.println("Changing name of "+clients[client_id].name+" to "+parsed[2]);
                  clients[client_id].name = parsed[2];
                  serverGui.updateGui(client_id,true);
                 // return "Name Changed to "+clients[client_id].name;
              }
              if(parsed[1].equalsIgnoreCase(UPDATE_POS))
              {
                  String[] pos = parsed[2].split(",");
                  System.out.println("Changing pos of "+clients[client_id].name+" to "+parsed[2]);
                  if(pos.length == 3)
                  {
                      clients[client_id].x_pos = Integer.valueOf(pos[0]).intValue();
                      clients[client_id].y_pos = Integer.valueOf(pos[1]).intValue();
                      clients[client_id].z_pos = Integer.valueOf(pos[2]).intValue();
                      serverGui.updateGui(client_id,false);
                  }
              }
          }
      }
      
      return null;
  }
  
  public void run() {
    String request;
    String out_data;
    boolean connected = true;
    int client_id = -1;
    System.out.println("Someones connecting...\n");
    try {
      PrintStream pstream = new PrintStream(csocket.getOutputStream());
      BufferedReader input = new BufferedReader(new InputStreamReader(csocket.getInputStream()));
            
      for(int i = 0; i < MAX_CLIENTS; i++)
      {
          if(clients[i].valid == false)
          {
              clients[i].valid = true;
              client_id = i;
              clients[i].uid = client_id;
              serverGui.updateGui(client_id,true);
              break;
          }
      }
      if(client_id == -1)
      {
          //Drop connection b/c clients are ful
          pstream.println("ROOM_FULL");
          connected = false;
      }
      
      while(connected)
      {
          if(clients[client_id].valid == false){ connected = false; break;}

          while((request = (input.readLine())) != null)
          {
             if(request.equalsIgnoreCase("quit") ||  clients[client_id].valid == false){ connected = false; break;}

             out_data = handle_request(client_id, request);
             if(out_data != null)
             {
                 pstream.println(out_data);
              }
          }
      }

      //Free Slot
      if(client_id >= 0) clients[client_id].valid = false;
      serverGui.updateGui(client_id,true);
      
      pstream.close();
      csocket.close();
    } catch (IOException e) {
      System.out.println(e);
    }
  }
}
     
